﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web.Mvc;

using ProjectBase.Core;
using ProjectBase.Core.Web;
using ProjectBase.Mvc;
using Survey.Common;

namespace Survey.Filters
{
    /// <summary>
    ///     This attribute is MUST. Do not switch it off!
    ///     Application Messages are one of the Application pillars..
    ///     During every Redirection of one compounded Requests, the messages are stored in the session and restored
    ///     until the real ViewAction result comes to play.
    ///     That allows to use Messages as really powerfull tool - You can put any error at any time and you can be sure
    ///     that it will bubble to user and to Transaction.Rollback, even in situations with multi RedirectToAction calls.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class MessagesFilterAttribute : ActionFilterAttribute, IPublishingReporter
    {
        #region OnAction
        /// <summary>
        ///     Restores messages from session if any.
        /// </summary>
        /// <param name = "filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            this.PublishInfo(() => "OnActionExecuting--started-MessagesFilter");
            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.Is())
            {
                RestoreMessages(filterContext);
            }
            this.PublishInfo(() => "OnActionExecuting-finished-MessagesFilter");
        }

        /// <summary>
        ///     Stores the Messages in the session if needed and restores selected tab
        /// </summary>
        /// <param name = "filterContext"></param>
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            this.PublishInfo(() => "OnActionExecuted--started-MessagesFilter");
            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.Is())
            {
                StoreMessages(filterContext);
            }
            this.PublishInfo(() => "OnActionExecuted-finished-MessagesFilter");
        }
        #endregion OnAction

        #region OnResult
        /// <summary>
        ///     Crucial cleaner of the Messages collection in cases, that multi RedirectToAction were in play.
        ///     This will evaluate if the result is finally ViewAction result (or similar) and then cleans Messages.
        /// </summary>
        /// <param name = "filterContext"></param>
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            this.PublishInfo(() => "OnResultExecuted-started-MessagesFilter");

            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.Is())
            {
                ClearMessages(filterContext);
            }

            this.PublishInfo(() => "OnResultExecuted-finished-MessagesFilter");
        }
        #endregion OnResult

        #region Messages
        /// <summary>
        ///     Restores Messages from the previous controler in the chain
        ///     of one request set
        /// </summary>
        /// <param name = "filterContext"></param>
        protected virtual void RestoreMessages(ActionExecutingContext filterContext)
        {
            if (filterContext.IsChildAction)
            {
                return;
            }

            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.IsNull())
            {
                return;
            }

            var messages = filterContext.Session()[Str.TempDataKeys.MessagesKey] as Messages;
            if (messages.IsNull())
            {
                return;
            }

            foreach (var message in messages)
            {
                controller.Model.Messages.Add(message);
            }
        }

        /// <summary>
        ///     Stores Messages for next Controller in the request set
        /// </summary>
        /// <param name = "filterContext"></param>
        protected virtual void StoreMessages(ActionExecutedContext filterContext)
        {
            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.IsNull()
              || controller.Model.Messages.IsEmpty())
            {
                return;
            }
            var messages = filterContext.Session()[Str.TempDataKeys.MessagesKey] as Messages;
            if (messages.IsNull())
            {
                messages = new Messages();
                filterContext.Session()[Str.TempDataKeys.MessagesKey] = messages;
            }
            foreach (var message in controller.Model.Messages)
            {
                if (!messages.Contains(message))
                {
                    messages.Add(message);
                }
            }
        }

        /// <summary>
        ///     Clears the Messages collection
        ///     when the View is rendered
        /// </summary>
        /// <param name = "filterContext"></param>
        protected virtual void ClearMessages(ResultExecutedContext filterContext)
        {
            if (filterContext.Result is RedirectToRouteResult
              || filterContext.Result is RedirectResult
              || filterContext.Result is PartialViewResult)
            {
                return;
            }

            var controller = filterContext.Controller as IWebController<IViewModel>;
            if (controller.Is())
            {
                filterContext.Session().Remove(Str.TempDataKeys.MessagesKey);
            }
        }
        #endregion Messages
    }
}